#ifndef _DECS_H_
#define _DECS_H_

#include <mqueue.h>
#include "decs_pub.h"
#include "hiredis.h"

#define decs_log_error(...) ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, __VA_ARGS__)
#define decs_log_debug(...) ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0, __VA_ARGS__)

typedef struct 
{
    int  id;
    char material[256];
    char click_url[256];
    char position;
    unsigned time_bits;
} ad_t;

#if 0
typedef struct 
{
    char domain[101];
    int  black;
    int  ad_id;
    int  ad_interval;
} dm_t;
#endif


typedef struct
{
	ngx_str_t name;
	ngx_str_t dm_file;
	ngx_str_t template;
	ngx_str_t redirect_url;
	pcre  *re_ua;
	unsigned weight;
    ngx_str_t clientip;
    char *templatedata;
    unsigned rate;
    int per_ip_policy;
    int per_ip_policy_dm;	
}policy_t;

#define POLICY_RES_FRAME 1    /* 直接回复一个html */
#define POLICY_RES_REDIR 2    /* 直接302到一个地址  */

typedef struct
{
	int type;
	char *content;
}policy_res_t;

typedef struct
{
    ngx_str_t domain;
    unsigned  ifwhite:1;
    unsigned  ifexactly:1;
    unsigned  iscookie:1;
    unsigned  isregular:1;
    unsigned  space:4;
    char  *re_url_str;
    pcre  *re_cookie;
	pcre  *re_url;
	policy_t *policy;
} dm_t;



typedef struct
{
	dm_t *dm;
	int weight;
	void *next;
}dm_policy_t;

typedef struct
{
    ngx_str_t dst_url;
    pcre  *re_surl;
} redirect_t;

typedef struct {
    ngx_str_t         ext;
    ngx_uint_t        deny;      /* unsigned  deny:1; */
} decs_ext_rule_t;

typedef struct {
    in_addr_t         mask;
    in_addr_t         addr;
    ngx_uint_t        deny;      /* unsigned  deny:1; */
} decs_ip_rule_t;

typedef struct {
    ngx_str_t         ua;
    ngx_uint_t        deny;      /* unsigned  deny:1; */
} decs_ua_rule_t;

typedef struct {
    ngx_str_t    domain;
    pcre        *re_cookie;
   //wangchen  start
	  pcre        *re_url;
	 //wangchen  end
} cookie_reduce_t;

typedef struct {
    char               *redis_ip;
    ngx_int_t           redis_port;
    redisContext       *redis_ctx;
    time_t              connect_time;
    unsigned            index;
    ngx_connection_t   *c;
    unsigned            connecting:1;
    unsigned            blocking:1; //blocking while connecting
} redis_t;

typedef struct {
    char *ip;
    int   port_for_pps;
    int   port_for_decs;
    struct sockaddr_in addr_for_decs;
} decs_t;

typedef struct {
    ngx_str_t       url;
    ngx_str_t       ad_id;
} fixed_url_ad_t;

typedef struct {
    ngx_str_t url_pattern;
    ngx_str_t ad_id;
    pcre     *regex;
} regex_url_ad_t;


typedef struct {
    //ngx_rbtree_t             rbtree;
    ngx_rbtree_node_t        node;
    int                      count;
    char                    *key;
}decs_rbtree_node_t;

typedef struct {
    ngx_rbtree_t                     rbtree;
    ngx_rbtree_node_t                sentinel;
    //ngx_queue_t                      queue;
    //ngx_atomic_t                     cold;
    //ngx_atomic_t                     loading;
    //off_t                            size;
} decs_rbtree_sh_t;


struct decs_cfg_t_
{
    ngx_flag_t          enabled;
    ngx_flag_t          cookie_mapping_enabled;
    ngx_flag_t          ad_enabled;
    ngx_pool_t         *pool;
    ngx_array_t        *ip_rules;
    ngx_array_t        *ua_rules;
    ngx_array_t        *redirect;
    redis_t             redis;
    ngx_array_t        *decs_array;
    ngx_conf_mysql_t    cfg_db;
    time_t              cookie_expire;
    time_t              cookie_map_interval;
    time_t              cfg_expire;
    time_t              cfg_sync_interval;
    time_t              user_ad_interval;
    time_t              user_ad_expire;
    ngx_str_t           sync_url;
    ngx_str_t           sync_domain;
    ngx_str_t           sync_redirect;
    time_t              sync_delay;
    ngx_str_t           area;
    ngx_str_t           url_tag;
    ngx_array_t        *url_ext;
    //char               *iframes[10];
    char               *ad_iframe;
    char               *cookie_iframe;
    ngx_hash_t          cookie_reduce_hash;
    ngx_hash_t          policy_domain_hash;
    void               *consistent_hash_ring;
    char               *rcvbuf;
    ngx_flag_t          httplog_enabled;
    ngx_array_t        *log_ip_rules;
    ngx_flag_t          log_ip_rule_default;
    ngx_array_t        *log_ext;
    ngx_array_t        *log_domain;
    ngx_flag_t          log_ext_deny;
    ngx_flag_t          log_ext_all;
    ngx_str_t           log_dir;
    ngx_int_t           log_disk_num;
    ngx_open_file_t   **log_files;
    ngx_open_file_t    *access_log;
    ngx_hash_t          log_domain_hash;
    /* non config fields */
    int                 raw_sock;
    int                 udp_sock;
    int                 log_sock;
    //int                 sync_sock;
    int                 request_id;
    int                 local_redis_idx;
    int                 local_decs_idx;
    mqd_t               mqd_send;
    mqd_t               mqd_recv; //todo: combine send and recv
    ngx_int_t           show_rate;
    ngx_int_t           click_rate;
    ngx_array_t        *fixed_url_ad;
    ngx_hash_t          fixed_url_ad_hash;
    ngx_array_t        *regex_url_ad;
    struct sockaddr_in  phone_decs_addr;
    struct sockaddr_in  log_server_addr;
    int                 policy_num;
    policy_t           *policys[100];
    ngx_shm_zone_t     *shm_zone;
    decs_rbtree_sh_t   *sh;
    ngx_slab_pool_t    *shpool;
};

typedef struct
{
    char host[256];
    char cookie[256];
    time_t sync_time;
    int    id;
} sync_para_t;

typedef struct 
{
    char id[40];
} user_t;

typedef struct
{
    ngx_str_t host;
    ngx_str_t uri;
    ngx_str_t cookie;
    ngx_str_t ua;
    ngx_str_t ext;
    user_t    u;
    ngx_str_t url;
    //ad_t      ad;
    int       id;
    int       pos;
    ngx_str_t     ad_id;
    struct iphdr *iph;
    u_char url_data[2048];
    int              vector[24];
    int              rc;
    pcre            *re_url;
} req_t;


void *cookie_sync_thread(decs_cfg_t *cfg);
void *cfg_sync_thread(decs_cfg_t *cfg);

redisReply *redis_get(const char *type, const void *key, int keylen);
int redis_set(redis_t *r, const char *type, const void *key, size_t keylen, 
    const void *value, size_t valuelen, int expire);
redisReply *redis_get_cookie(const ngx_str_t *host, const ngx_str_t *cookie);
int redis_set_cookie(redis_t *r, const char *host, const char *cookie, 
    const void *value, size_t valuelen, int expire);
int redis_get_user(user_t *u);
void request_sync_data(req_t *r);
int decs_sync_start();

void *decs_create_conf(ngx_cycle_t *cycle);
char *decs_init_conf(ngx_cycle_t *cycle, void *conf);
char *decs_set_redis_addr(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_decs_addr(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_log_addr(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_ad_iframe(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_cookie_iframe(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_ip_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_log_ip_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_log_ext_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_ua_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_domain_list(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_int_t decs_init_module(ngx_cycle_t *cycle, decs_cfg_t *cfg);
void redis_close(redis_t *r, ngx_uint_t state);
void *redis_cmd(redis_t *r, const char *format, ...);
char *decs_set_access_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_redirect_list(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
int UrlEncode(char *src, int src_len, char *dst, int size);
char *decs_set_regex_url_ad(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_fixed_url_ad(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_phone_decs_addr(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_ad_policy_list(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *decs_set_shared_mem(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

extern decs_cfg_t *decs_cfg;

#endif
